﻿/*
COPYRIGHT (C) 2011-2013 Raynald Messié

THIS FILE IS PART OF SCRUMPILOT.

SCRUMPILOT IS FREE SOFTWARE: YOU CAN REDISTRIBUTE IT AND/OR MODIFY IT UNDER THE TERMS OF 
THE GNU LESSER GENERAL PUBLIC LICENSE VERSION v2.1 AS PUBLISHED BY THE FREE SOFTWARE FOUNDATION.

SCRUMPILOT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY; WITHOUT
EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU LESSER
GENERAL PUBLIC LICENSE FOR MORE DETAILS.

YOU SHOULD HAVE RECEIVED A COPY OF THE GNU LESSER GENERAL PUBLIC LICENSE ALONG WITH SCRUMPILOT. 
IF NOT, SEE <HTTP://WWW.GNU.ORG/LICENSES/>.
*/

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace ScrumPilot.TFSHelpers
{
    public partial class TFSServices
    {
        /// <summary>
        /// Uri of TF server
        /// </summary>
        public Uri TFSUri { get; set; }

        /// <summary>
        /// Simple ID+PWD credential
        /// </summary>
        public NetworkCredential TFSNetCredential { get; set; }

        private TfsTeamProjectCollection _tfs;

        /// <summary>
        /// Get a connected TFS instance
        /// </summary>
        public TfsTeamProjectCollection TfsServer
        {
            get
            {
                // If tfs object is initialize and not authentifiate : set to null to re-initialize
                if (_tfs != null && !_tfs.HasAuthenticated)
                    _tfs = null;
                return _tfs ??
                   (_tfs = new TfsTeamProjectCollection(TFSUri, TFSNetCredential));
            }
        }

        private WorkItemStore _wis;

        public WorkItemStore TfsWorkItemStore
        {
            get { return _wis ?? (_wis = TfsServer.GetService<WorkItemStore>()); }
        }

        private VersionControlServer _tfsVC;

        protected VersionControlServer TfsVersionControlServer
        {
            get { return _tfsVC ?? (_tfsVC = (VersionControlServer)TfsServer.GetService(typeof(VersionControlServer))); }
        }

        private IGroupSecurityService _tfsGss;

        protected IGroupSecurityService TfsGroupSecurityService
        {
            get { return _tfsGss ?? (_tfsGss = (IGroupSecurityService)TfsServer.GetService(typeof(IGroupSecurityService))); }
        }

        private ICommonStructureService4 _tfsCss;

        protected ICommonStructureService4 TfsCommonStructureService
        {
            get { return _tfsCss ?? (_tfsCss = (ICommonStructureService4)TfsServer.GetService(typeof(ICommonStructureService4))); }
        }

        /*
         *  var css4 = collection.GetService<ICommonStructureService4>();
         */
        private IEventService _tfsEvt;

        protected IEventService TfsEventService
        {
            get { return _tfsEvt ?? (_tfsEvt = (IEventService)TfsServer.GetService(typeof(IEventService))); }
        }

        public Identity currentUser { get; private set; }

        public Boolean IsAuthenticated { get { return _tfs != null && _tfs.HasAuthenticated; } }

        public String DisplayName { get { return currentUser.DisplayName; } }

        public int CurrentUserSPID { get; private set; }

        public TFSServices()
        {
        }

        public TFSServices(String url, String id, String pwd)
            : this()
        {
            TFSUri = new Uri(url);
            TFSNetCredential = new NetworkCredential(id, pwd);
        }

        public void RefreshCache()
        {
            this.TfsWorkItemStore.RefreshCache();
        }

        public void SynchroCache()
        {
            this.TfsWorkItemStore.SyncToCache();
        }

        public void RefreshAndSynchroCache()
        {
            this.TfsWorkItemStore.RefreshCache();
            this.TfsWorkItemStore.SyncToCache();
        }

        public bool Authenticate()
        {
            if (IsAuthenticated == false)
            {
                try
                {
                    // Ensure the current user can authenticate with TFS
                    TfsServer.EnsureAuthenticated();
                    // If it's ok, get the user information
                    currentUser = GetTFSIndentity(_tfs.AuthorizedIdentity.Descriptor.Identifier);

                    this.RefreshAndSynchroCache();
                }
                catch (Exception)
                {
                    return false;
                }

            }
            return IsAuthenticated;
        }

        /// <summary>
        /// Give the entire project list (name)
        /// </summary>
        /// <returns>List of projects name</returns>
        public List<String> GetProjects()
        {
            var pc = TfsWorkItemStore.Projects;
            var sRet = new List<String>(pc.Count);
            sRet.AddRange(pc.Cast<Project>().Select(p => p.Name));
            return sRet;
        }

        /// <summary>
        /// Give the entire project list (name)
        /// </summary>
        /// <returns>List of projects name</returns>
        public Dictionary<Int32, String> GetDictProjects()
        {
            var pc = TfsWorkItemStore.Projects;
            var sRet = new Dictionary<int, string>(pc.Count);
            foreach (Project prj in pc)
            {
                sRet.Add(prj.Id, prj.Name);
            }
            return sRet;
        }

        /// <summary>
        /// Give the entire project list (id)
        /// </summary>
        /// <returns>List of projects id</returns>
        public List<int> GetSIDProjects()
        {
            var iRet = new List<int>();
            var pc = TfsWorkItemStore.Projects;
            iRet.AddRange(from Project p in pc select p.Id);

            return iRet;
        }

        /// <summary>
        /// Give the entire project list (id)
        /// </summary>
        /// <returns>List of projects id</returns>
        public Project GetProject(int id)
        {
            try
            {
                return TfsWorkItemStore != null ? TfsWorkItemStore.Projects.GetById(id) : null;
            }
            catch (Exception)
            {
                return null;
            }
        }

        public List<TFSWallContentObjectWithUser> GetCheckOut(String sid, String projectName)
        {
            var lstRet = new List<TFSWallContentObjectWithUser>();
            if (TfsVersionControlServer != null)
                lstRet = getCheckOutItems(TfsVersionControlServer.QueryWorkspaces(null, sid, null),
                                               projectName);

            return lstRet;
        }

        public List<TFSTimeLineObject> GetHistoryChangeSet(String sid, DateTime dateMin, Nullable<DateTime> dateMax = null)
        {
            if (TfsVersionControlServer != null)
            {
                //here you specify the exact time period you need to get the change set (from Date,to Date)
                VersionSpec fromDateVersion = new DateVersionSpec(dateMin);
                VersionSpec toDateVersion = new DateVersionSpec(dateMax ?? DateTime.UtcNow.Date.AddDays(1));
                // using versionControl API you can query histroy for changes set for (specific,all) user
                var changeSets = TfsVersionControlServer.QueryHistory("$/", VersionSpec.Latest, 0, RecursionType.Full, sid, fromDateVersion, toDateVersion, int.MaxValue, true, true).Cast<Changeset>();
                var lstRet = new List<TFSTimeLineObject>();
                foreach (var changeset in changeSets)
                {
                    var name = changeset.Changes.Aggregate("", (current, change) => current + (" ," + change.Item.ServerItem)).Substring(2);
                    lstRet.Add(new TFSTimeLineObject
                                   {
                                       ID=changeset.ChangesetId,
                                       WorkItemType = "Changeset",
                                       Name = changeset.Comment,
                                       Date = changeset.CreationDate,
                                       Descriptions = name,
                                       State = "Checkout"
                                   });
                }
                return lstRet;
            }

            return null;
        }



        public List<TFSWallContentObjectWithUser> GetCheckOut(String projectName)
        {
            return GetCheckOut(null, projectName);
        }

        private List<TFSWallContentObjectWithUser> getCheckOutItems(IEnumerable<Workspace> workspaceList, String projectName)
        {
            var lstRet = new List<TFSWallContentObjectWithUser>();
            foreach (Workspace wkp in workspaceList)
            {
                var pendingChanges = wkp.GetPendingChanges(new[] { "$/" + projectName }, RecursionType.Full);

                lstRet.AddRange(from p in pendingChanges
                                where p.ChangeType != Microsoft.TeamFoundation.VersionControl.Client.ChangeType.None &&
                                      p.ItemType == ItemType.File
                                select new TFSWallContentObjectWithUser
                                           {
                                               Id = p.ItemId,
                                               Name = p.ServerItem,
                                               Date = p.CreationDate,
                                               Username = wkp.OwnerName,
                                               ProjectName = projectName
                                           });
            }
            return lstRet.OrderBy(p => p.Name).ToList();
        }

        public List<TFSWallContentObjectWithUser> GetAllPendingChange()
        {
            var wkp = TfsVersionControlServer.QueryWorkspaces(null, null, null);
            return getCheckOutItems(wkp, "");
        }

        public String GetSource(String sourceName)
        {
            var item = TfsVersionControlServer.GetItem(sourceName, VersionSpec.Latest);
            var st = item.DownloadFile();
            var sr = new StreamReader(st);

            return sr.ReadToEnd();
        }

        public void ScanAllLastSource()
        {
            var items = TfsVersionControlServer.GetItems("$/*");
        }

        public TFSScheduleInfo GetIterationSchedule(string iterationPath)
        {
            TFSScheduleInfo mySchedule = null;
            var projectNameIndex = iterationPath.IndexOf("\\", 2, StringComparison.Ordinal);
            var fullPath = projectNameIndex >= 0 ? iterationPath.Insert(projectNameIndex, "\\Iteration") :
                iterationPath + "\\Iteration";
            var nodeInfo = this.TfsCommonStructureService.GetNodeFromPath(fullPath);
            if (nodeInfo != null)
                mySchedule = new TFSScheduleInfo
                                 {
                                     StartDate = nodeInfo.StartDate,
                                     FinishDate = nodeInfo.FinishDate
                                 };
            return mySchedule;
        }

        /// <summary>
        /// Search a specific Iteration in all IterationNode from a
        /// collection of nodes (typicaly from IterationRootNodes)
        /// </summary>
        /// <param name="nodes">Nodes collection</param>
        /// <param name="id">Id of searched iteration</param>
        /// <returns>Node if found or null</returns>
        public Node RecursiveSearchIterationPath(NodeCollection nodes, int id)
        {
            foreach (Node item in nodes)
            {
                if (item.Id == id)
                    return item;
                if (item.HasChildNodes)
                {
                    return RecursiveSearchIterationPath(item.ChildNodes, id);
                }
            }
            return null;
        }

    }

    public class TFSWallContentObject
    {
        public int ID { get; set; }
        public String Name { get; set; }
        public String Descriptions { get; set; }
        public String More { get; set; }
        public String Url { get; set; }
        public String ProjectName { get; set; }
        public String Iteration { get; set; }
        public String WorkItemType { get; set; }
        public String HourStatus { get; set; }
        public Boolean ChangeState { get; set; }
        public DateTime Date { get; set; }
    }

    public class TFSWallContentObjectWithUser : TFSWallContentObject
    {
        public Int32 Id { get; set; }
        public String Username { get; set; }
        public Nullable<Int32> UserID { get; set; }
    }

    public class TFSTimeLineObject : TFSWallContentObject
    {
        public String State { get; set; }
    }

    public class TFSScheduleInfo
    {
        public Nullable<DateTime> StartDate { get; set; }
        public Nullable<DateTime> FinishDate { get; set; }
    }
}